#include "../../include/graphics/PostProcessor.hpp"
#include "../../include/graphics/gl/GLRenderToTexture.hpp"
using namespace klas;
using namespace graphics;

/* Batch */

PostProcessorBatch::Batch::Batch()
: alpha(1.0f)
{
  shader = 0;
}

PostProcessorBatch::Batch::Batch(graphics::ShaderProgram *shader, decimal alpha)
{
  this->alpha = alpha;
  this->shader = shader;
}


/* Post Processor Batch */


PostProcessorBatch::PostProcessorBatch()
  : m_finalEffectAlpha(1.0f)
{
}

PostProcessorBatch::PostProcessorBatch(const vector<Batch>& effect, decimal finalEffectAlpha)
  : m_finalEffectAlpha(finalEffectAlpha)
{
  m_effects = effect;
}

void PostProcessorBatch::setFinalEffectAlpha(decimal alpha)
{
  m_finalEffectAlpha = alpha;
}

void PostProcessorBatch::addEffect(ShaderProgram* effect, decimal alpha)
{
  addBatch(PostProcessorBatch::Batch(effect, alpha));
}

void PostProcessorBatch::addBatch(const Batch& batch)
{
  m_effects.push_back(batch);
}

void PostProcessorBatch::renderEffects(RenderToTexture* renderToA, RenderToTexture* renderToB, const math::Vector2d& numSides)
{
  // Is the most active render on a?
  bool currentOnA = true;

  // iterate all effects and render them
  for(uint32 i = 0; i < m_effects.size(); ++i)
  {
    m_effects[i].shader->enable();

    if(i % 2)
    {
      renderToA->enable();
      renderToB->render(numSides, m_effects[i].alpha * m_finalEffectAlpha);
      currentOnA = true;
    }
    else
    {
      renderToB->enable();
      renderToA->render(numSides, m_effects[i].alpha * m_finalEffectAlpha);
      currentOnA = false;
    }
  }

  // disable shaders
  if(m_effects.size() >= 1)
    m_effects[0].shader->disable();

  // make sure that the latest version is on render target a
  if(currentOnA == false)
  {
    renderToA->enable();
    renderToB->render(numSides, 1.0f);
  }

  // turn of the render targets
  renderToA->disable();

}





/* Post Processor */

PostProcessor::PostProcessor(const math::Vector2<uint32>& dim)
{
  m_textureA = new graphics::gl::GLRenderToTexture(dim);
  m_textureB = new graphics::gl::GLRenderToTexture(dim);
  m_batches.clear();
  m_batchQuads.clear();
}

PostProcessor::~PostProcessor()
{
  klasDelete(m_textureA);
  klasDelete(m_textureB);
}

void PostProcessor::startedRendering()
{
  m_textureA->enable();
}

void PostProcessor::finishedRendering()
{
  m_textureA->disable();
}

void PostProcessor::addBatch(const PostProcessorBatch& batch, const math::Vector2d& quads)
{
  m_batches.push_back(batch);
  m_batchQuads.push_back(quads);
}

void PostProcessor::render()
{
  for(uint32 i = 0; i < m_batches.size(); ++i)
    m_batches[i].renderEffects(m_textureA, m_textureB, m_batchQuads[i]);

  m_textureA->render(math::Vector2d(1, 1), 1.0f);
}